package at.fhj.itm10.ticketmaster.services;

import java.sql.Connection;
import java.sql.SQLException;

import javax.faces.context.FacesContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
import javax.sql.DataSource;

import org.apache.log4j.Logger;

import at.fhj.itm10.ticketmaster.dao.AddressDAO;
import at.fhj.itm10.ticketmaster.dao.CustomerDAO;
import at.fhj.itm10.ticketmaster.dao.EventTypeDAO;
import at.fhj.itm10.ticketmaster.dao.EventDAO;
import at.fhj.itm10.ticketmaster.dao.OrderDAO;
import at.fhj.itm10.ticketmaster.dao.TicketDAO;
import at.fhj.itm10.ticketmaster.services.datasource.DataSourceLocator;
import at.fhj.itm10.ticketmaster.services.impl.AddressServiceImpl;
import at.fhj.itm10.ticketmaster.services.impl.CartServiceImpl;
import at.fhj.itm10.ticketmaster.services.impl.CustomerServiceImpl;
import at.fhj.itm10.ticketmaster.services.impl.EventTypeServiceImpl;
import at.fhj.itm10.ticketmaster.services.impl.EventServiceImpl;
import at.fhj.itm10.ticketmaster.services.impl.OrderServiceImpl;
import at.fhj.itm10.ticketmaster.services.impl.TicketServiceImpl;
import at.fhj.itm10.ticketmaster.services.res.ResourceXmlChecker;

/**
 * Service factory implementation.
 * 
 * @author Wolfgang Gaar, Kevin Reinmueller
 */
public class ServiceFactory {

	private Logger logger = Logger.getLogger(ServiceFactory.class);
	private ServletContext servletContext = null;

	public ServiceFactory() {
		logger.debug("construction of ServiceFactoryImpl");
	}

	public CustomerService getCustomerService() {
		logger.debug("getCustomerService()");
		setResources();
		logger.debug("after resources.xml check");

		Connection connection = retrieveConnection();
		CustomerDAO dao = new CustomerDAO(connection);
		AddressDAO addressDao = new AddressDAO(connection);
		CustomerServiceImpl service = new CustomerServiceImpl();

		service.setConnection(connection);
		service.setDao(dao);
		service.setAddressDao(addressDao);

		return service;
	}

	public AddressService getAddressService() {
		logger.debug("getAddressService()");
		setResources();
		logger.debug("after resources.xml check");

		Connection connection = retrieveConnection();		
		AddressDAO addressDao = new AddressDAO(connection);
		AddressServiceImpl service = new AddressServiceImpl();

		service.setConnection(connection);
		service.setAddressDao(addressDao);

		return service;
	}
	
	public OrderService getOrderService() {
		logger.debug("getOrderService()");
		setResources();
		logger.debug("after resources.xml check");

		Connection connection = retrieveConnection();		
		OrderDAO orderDao = new OrderDAO(connection);
		OrderServiceImpl service = new OrderServiceImpl();

		service.setConnection(connection);
		service.setDao(orderDao);

		return service;
	}
	
	public TicketService getTicketService() {
		logger.debug("getTicketService()");
		setResources();
		logger.debug("after resources.xml check");

		Connection connection = retrieveConnection();		
		TicketDAO ticketDao = new TicketDAO(connection);
		TicketServiceImpl service = new TicketServiceImpl();

		service.setConnection(connection);
		service.setDao(ticketDao);

		return service;
	}
	
	public EventService getEventService() {
		logger.debug("getEventService()");
		setResources();
		logger.debug("after resources.xml check");

		Connection connection = retrieveConnection();		
		EventDAO eventDao = new EventDAO(connection);
		EventServiceImpl service = new EventServiceImpl();

		service.setConnection(connection);
		service.setEventdao(eventDao);

		return service;
	}
	

	/**
	 * Gets a database connection.
	 * 
	 * @return Connection
	 */
	private Connection retrieveConnection() {
		logger.debug("retrieveConnection()");
		setResources();
		logger.debug("after resources.xml check");

		try {
			DataSource source = (new DataSourceLocator()).getDataSource();
			logger.info("retrieved datasource = " + source);

			return source.getConnection();
		} catch (NamingException e) {
			logger.debug("JNDI resource not found. does resources.xml exist?", e);

			throw new ServiceException(e);
		} catch (SQLException e) {
			logger.debug("problem during connection setup", e);

			throw new ServiceException(e);
		}
	}
	
	public CartService getCartService() {
		logger.debug("createCartService()");
		setResources();
		logger.debug("after resources.xml check");

		CartService cartservice = new CartServiceImpl();

		return cartservice;
	}
	
	public EventTypeService getEventTypeService() {
		logger.debug("getEventTypeService()");
		setResources();
		logger.debug("after resources.xml check");

		Connection connection = retrieveConnection();		
		EventTypeDAO eventTypeDao = new EventTypeDAO(connection);
		EventTypeServiceImpl service = new EventTypeServiceImpl();

		service.setConnection(connection);
		service.setEventTypeDao(eventTypeDao);

		return service;
	}
	
	// do not modify visibility: needed for test!
	protected void setResources() {
		logger.debug("setResources()");
		
		try {
			if(servletContext != null) {
				return;
			}

			servletContext = (ServletContext) FacesContext.getCurrentInstance()
					.getExternalContext().getContext();

			new ResourceXmlChecker(servletContext);
		} catch (Exception e) {
			throw new ServiceException("resources not found", e);
		}
	}

}
